#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"

namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;

    static const int gcap = 10;

    template <typename T>
    class BlockQueue
    {
    public:
        BlockQueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
        {
        }
        void Equeue(const T&in)
        {
            LockGuard lockguard(_mutex);
            while(IsFull())
            {
                std::cout << "生产者进入等待..." << std::endl;
                _pwait_num++;
                _productor_cond.Wait(_mutex);
                _pwait_num--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            _q.push(in);
            if(_cwait_num){
                std::cout << "叫醒消费者" << std::endl;
                _consumer_cond.Notify();
            }
        }
        void Pop(T* out)
        {
            LockGuard lockguard(_mutex);
            while(IsEmpty())
            {
                std::cout << "消费者进入等待..." << std::endl;
                _cwait_num++;
                _consumer_cond.Wait(_mutex); // 伪唤醒
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl;
            }
            *out = _q.front();
            _q.pop();

            if(_pwait_num)
            {
                std::cout << "叫醒生产者" << std::endl;
                _productor_cond.Notify();
            }
        }
        ~BlockQueue(){}
    private:
        bool IsFull(){return _q.size() == _cap;}
        bool IsEmpty(){return _q.empty();};
        std::queue<T> _q;
        int _cap;
        Mutex _mutex;
        Cond _productor_cond;
        Cond _consumer_cond;
        int _cwait_num;
        int _pwait_num;
    };
}